package com.snowfield.lb47.lbconfig.velocityService;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.snowfield.lbcommon.domain.Cluster;
import com.snowfield.lbcommon.config.SnowFieldConfig;
import com.snowfield.lbcommon.velocity.keepalived.KeepalivedConfig;
import com.snowfield.lbcommon.velocity.keepalived.VRRPInstance;
import com.snowfield.lbcommon.velocity.util.VelocityInitializer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.List;

@Service
public class KAVelocityService {

    /**
     * 生成keepalived配置文件内容
     * @param cluster 集群信息
     * @param staticIpAddressList 静态IP地址列表
     * @param virIpAddressListA 虚IP地址列表A
     * @param virIpAddressListB 虚IP地址列表B
     */
    public void createKeepalivedConfigFile(Cluster cluster, List<String> staticIpAddressList, List<String> virIpAddressListA, List<String> virIpAddressListB) {
        KeepalivedConfig keepalivedConfig = createKeepalivedConfig(cluster, staticIpAddressList, virIpAddressListA, virIpAddressListB);

        VelocityInitializer.initVelocity();
        VelocityContext context = prepareContext(keepalivedConfig);

        // 渲染模板
        StringWriter sw = new StringWriter();
        String template = "vm/keepalived.conf.vm";
        Template tpl = Velocity.getTemplate(template, "UTF-8");
        tpl.merge(context, sw);
        try {
            String configFilePath = SnowFieldConfig.getKaConfigPath() + "/keepalived-velocity.conf";
//            String configFilePath = "/etc/keepalived/keepalived.conf";
            FileUtils.write(new File(configFilePath), sw.toString(), Charset.forName("UTF-8"));
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }

    /**
     * 生成Keepalived配置文件对象数据
     * @param cluster 集群信息
     * @param staticIpAddressList
     * @param virIpAddressListA 虚IP地址列表A
     * @param virIpAddressListB 虚IP地址列表B
     * @return
     */
    public KeepalivedConfig createKeepalivedConfig(Cluster cluster, List<String> staticIpAddressList, List<String> virIpAddressListA, List<String> virIpAddressListB) {
        KeepalivedConfig keepalivedConfig = new KeepalivedConfig();

        keepalivedConfig.setNodeName(cluster.getNodeName());
        keepalivedConfig.setDevice(cluster.getDeviceType());
        keepalivedConfig.setMode(cluster.getMode());

        //static address
        keepalivedConfig.setStaticIpAddressList(staticIpAddressList);


        //设置虚地址绑定的网卡名称,如果未读取到配置，默认为eth0
        String kaInterfaceName = SpringUtils.getBean(RedisCache.class).getCacheObject("keepalived:interfaceName");
        String deviceType = cluster.getDeviceType();

        /**
         * 如果集群模式为主从模式，只配置一个主虚拟路由即可
         */
        if ("MB".equals(cluster.getMode())) {
            /**
             * 主虚拟路由配置
             */
            VRRPInstance masterVrrpInstance = new VRRPInstance();
            String masterState = "MASTER";
            if (StringUtils.isBlank(deviceType) || deviceType.equals("master")){
                masterState = "MASTER";
            } else if (deviceType.equals("backup")){
                masterState = "BACKUP";
            }
            //vrrp状态
            masterVrrpInstance.setState(masterState);

            //绑定接口
            if (StringUtils.isNotEmpty(kaInterfaceName)) {
                masterVrrpInstance.setInterfaceName(kaInterfaceName);
            }
            masterVrrpInstance.setVirRouterId(cluster.getVirrouterId());
            masterVrrpInstance.setPriority(cluster.getPriority());
            //通信协议：组播，单播
            masterVrrpInstance.setVrrpProto(cluster.getVrrpProto());
            //单播时设置本机地址及对端地址
            masterVrrpInstance.setSrcIp(cluster.getDeviceIp());
            masterVrrpInstance.setPeerIp(cluster.getPeerIp());

            /**
             * vip address，
             * 因为是主从模式，将virIpAddressListA和virIpAddressListB中的地址合并后绑定在一个虚拟路由中
             */
            virIpAddressListA.addAll(virIpAddressListB);
            masterVrrpInstance.setVirIpAddressList(virIpAddressListA);

            keepalivedConfig.setMasterInstance(masterVrrpInstance);
        } else if ("MM".equals(cluster.getMode())){
            /**
             * 后台【机器人攻击防护】功能未生效！如有需要请联系作者QQ:3961919621
             */
        }

        return keepalivedConfig;
    }

    /**
     * 设置模板变量信息
     *
     * @return 模板列表
     */
    public VelocityContext prepareContext(KeepalivedConfig keepalivedConfig) {
        VelocityContext velocityContext = new VelocityContext();

        velocityContext.put("nodeName", keepalivedConfig.getNodeName());
        velocityContext.put("staticIpAddressList", keepalivedConfig.getStaticIpAddressList());
        velocityContext.put("masterInstance", keepalivedConfig.getMasterInstance());
        velocityContext.put("backupInstance", keepalivedConfig.getBackupInstance());

        return velocityContext;
    }

    /**
     * 备份
     */
    public static void backupKAConfigFile() {
        File originFile = new File(SnowFieldConfig.getKaConfigPath() + "/keepalived-velocity.conf");
        File backupFile = new File(SnowFieldConfig.getKaConfigPath() + "/keepalived-velocity.conf.bak");
        if (originFile.exists()) {
            try {
                FileUtils.copyFile(originFile, backupFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 恢复
     */
    public static void restoreKAConfigFile() {
        File originFile = new File(SnowFieldConfig.getKaConfigPath() + "/keepalived-velocity.conf");
        File backupFile = new File(SnowFieldConfig.getKaConfigPath() + "/keepalived-velocity.conf.bak");
        if (backupFile.exists()) {
            try {
                FileUtils.copyFile(backupFile, originFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
